﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;

namespace Mindfor.Web.Routing
{
	/// <summary>
	/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
	/// </summary>
	[AttributeUsage(AttributeTargets.Method, Inherited=true, AllowMultiple=true)]
	public class UrlRouteConstraintAttribute : Attribute
	{
		Type m_constraintType;

		/// <summary>
		/// Gets or sets route index constraint belong to.
		/// If action has only one route than route index can be 0.
		/// </summary>
		public int RouteIndex { get; set; }

		/// <summary>
		/// Gets or sets name of the route parameter on which to apply the constraint.
		/// </summary>
		public string Name { get; set; }

		/// <summary>
		/// Gets or sets regular expression constraint to test on the route parameter value in the URL.
		/// </summary>
		public string Regex { get; set; }

		/// <summary>
		/// Gets or sets constraint type to use. Must implement IRouteConstraint interface.
		/// </summary>
		public Type ConstraintType
		{
			get { return m_constraintType; }
			set
			{
				if (value != null && !typeof(IRouteConstraint).IsAssignableFrom(value))
					throw new ArgumentException("Value must implement IRouteConstraint interface.", "value");
				m_constraintType = value;
			}
		}

		/// <summary>
		/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
		/// </summary>
		/// <param name="routeIndex">Route index constraint belong to.
		/// If action has only one route than route index can be null.</param>
		/// <param name="name">Name of the route parameter on which to apply the constraint.</param>
		/// <param name="regex">Regular expression constraint to test on the route parameter value in the URL.</param>
		public UrlRouteConstraintAttribute(int routeIndex, string name, string regex)
		{
			RouteIndex = routeIndex;
			Name = name;
			Regex = regex;
		}

		/// <summary>
		/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
		/// </summary>
		/// <param name="name">Name of the route parameter on which to apply the constraint.</param>
		/// <param name="regex">Regular expression constraint to test on the route parameter value in the URL.</param>
		public UrlRouteConstraintAttribute(string name, string regex)
			: this(0, name, regex)
		{
		}

		/// <summary>
		/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
		/// </summary>
		/// <param name="routeIndex">Route index constraint belong to.
		/// If action has only one route than route index can be null.</param>
		/// <param name="name">Name of the route parameter on which to apply the constraint.</param>
		/// <param name="constraintType">Constraint type to use. Must implement IRouteConstraint interface.</param>
		public UrlRouteConstraintAttribute(int routeIndex, string name, Type constraintType)
		{
			RouteIndex = routeIndex;
			Name = name;
			ConstraintType = constraintType;
		}

		/// <summary>
		/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
		/// </summary>
		/// <param name="name">Name of the route parameter on which to apply the constraint.</param>
		/// <param name="constraintType">Constraint type to use. Must implement IRouteConstraint interface.</param>
		public UrlRouteConstraintAttribute(string name, Type constraintType)
			: this(0, name, constraintType)
		{
		}

		/// <summary>
		/// Creates object by ConstraintType. Returns null if constraint type is not defined.
		/// </summary>
		public IRouteConstraint CreateConstraint()
		{
			if (ConstraintType == null)
				return null;

			return (IRouteConstraint)Activator.CreateInstance(ConstraintType);
		}
	}
}
